/**
 * 
 */
package gen;

import java.io.File;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import sources.AdvancedFileSource;

import com.google.common.base.Charsets;
import com.google.common.io.Files;

/**
 * @author Kyniek
 *
 */
public class GeneratorMain
{
	
	Schema schema;
	
	public static final ApplicationContext context = new ClassPathXmlApplicationContext("springBeans.xml");
	
	static SqlSessionFactory sqlMapper;

	static SqlSessionFactory trgMapper;
	
	public static final String selSingle = "sel_single";
	
	public static final String selHashMap = "sel_map";
	

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception
	{
		//testowanie nowych finkcjonalności 
//		AdvancedFileSource adv = (AdvancedFileSource) context.getBean("test_source");
//		
//		for(int i = 0; i < 100; i++)
//		{
//			System.out.println("VAL : " + adv.get());
//		}
		
		
		GeneratorMain gen = new GeneratorMain();
		
//		int arr[] = new int[]{1,4,6,7,8,10,19,20,30,42,50,59,64,70,80,90,100,143,154,165,176,187,190,203,210,210,223,243,254,266,276,287,290,299,300,311,312,322,329,331,335,337,339,342,
//				349,351,360,365,373,376,377,379,383,385,387,389,391,393,396,398,400,403,406,409,410,414,418,420,422,425,426,429,432,435,437,439,441,443,445,447,449,450,453,456,459,460,
//				1000,1500,1900,2500,4000};
//		
//		int target = 4001;
//		int indexStart = arr.length/2;
//		int indexRet = 0;
//		int indexBeg = 0;
//		int indexEnd = arr.length - 1;
//		
//		while( indexBeg <= indexEnd )
//		{
//			if(target == arr[indexStart])
//			{
//				break;
//			}
//			if(target < arr[indexStart])//jeśli jest po lewo
//			{
//				indexEnd = indexStart;
//				indexStart = indexStart - (indexEnd - indexBeg )/2;  //2;
//				System.out.println("lewo : " + indexStart + " beg : " + indexBeg + " end : " + indexEnd);
//				if(target <= arr[indexBeg])
//				{
//					indexStart = indexBeg;
//					break;
//				}
//				
//				if(indexStart == indexEnd)
//				{
//					break;
//				}				
//			}
//			else if(target > arr[indexStart])//jeśli jest po prawo....
//			{
//				indexBeg = indexStart;
//				indexStart = indexStart + (indexEnd - indexBeg)/2;
//				System.out.println("prawo : " + indexStart + " beg : " + indexBeg + " end : " + indexEnd);//prawo : 1 beg : 1 end : 2
//				if(target >= arr[indexEnd] || indexStart == indexBeg)
//				{
//					indexStart = indexEnd;
//					break;
//				}
//			}			
//		}
//		System.out.println(indexStart + " : " + arr[indexStart] + " trg : " + target);
	

	}
	
	
	
	public GeneratorMain() throws Exception
	{
		
        System.out.println("Creating Schema...");		
		Schema sh = (Schema) context.getBean("schema");
		System.out.println("mapper : \n" + generateMapperCode(sh) + "\n\n============" );
		Files.write(generateMapperCode(sh), new File(sh.getMapperLocation()), Charsets.ISO_8859_1);
		
		System.out.println("Initializing DB...");
		String resource = "BatisConf.xml";
		Reader reader = Resources.getResourceAsReader(resource);
		if(sh.getTmpSchema() != null)
		{
			sqlMapper = new SqlSessionFactoryBuilder().build(reader, sh.getTmpSchema());
		}
		reader = Resources.getResourceAsReader(resource);
		
		if(sh.getTargetSchema() != null)
		{
			trgMapper = new SqlSessionFactoryBuilder().build(reader, sh.getTargetSchema());
		}
		else
		{
			trgMapper = new SqlSessionFactoryBuilder().build(reader);//development
		}
		
		System.out.println("Init Schema...");
		initSchema(sh);		
		
		System.out.println("Data generated successfully");
	}
	
	public GeneratorMain(Schema sh)
	{
		initSchema(sh);
	}

	

	/**
	 * Funkcje generatora :
	 * - generuje kod XML dla mapper.xml dla MyBatisa (instrukcje create table oraz inserty i update)
	 * - wygenerowany insert pobiera hashMapę reprezentującą wiersz, klucze są równoczesnie nazwami kolumn
	 * - wygenerowany update pobiera hashMapę 
	 * - powinien wygenerować kompletny plik mapper.xml
	 * - ID wygenerowanej instrukcji powinno być jakoś przekazywane do obiektu Table
	 * 
	 * Działanie : 
	 * 1) ze schematu pobiera listę tabel
	 * 2) z tabel pobiera ich nazwy, dalej pobiera źródła
	 * 3) ze źródeł pobiera nazwy kolumn oraz... typu?
	 * 4) generuje inserta dla konkretnej tabeli i zapisuje ID w obiekcie Table
	 * 5) generuje instrukcję update po ID 
	 * @param sh
	 * @return
	 */
	public String generateMapperCode(Schema sh)
	{	 
		String code = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
				"<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n" +
				"<mapper namespace=\"kynNamespace\">\n" +	
				"<update id=\"createTab\" parameterType=\"hashmap\">\n" +
				"CREATE TABLE ${tab} ( ${cols} )\n" +	
				"</update>\n\n" +	
				"<update id=\"update_where\" parameterType=\"hashmap\">\n" +
				"update ${tab} SET ${col} = #{val} WHERE ${col2} = #{val2}" +
				"</update>\n\n" +	
				"<update id=\"dropTab\" >\n" +
				"DROP TABLE  ${tab} CASCADE CONSTRAINTS\n"+		
				"</update>\n\n"	+
				"<update id=\"cmd\" parameterType=\"String\">\n" +
				"${value}\n" +
				"</update>\n\n" +
				"<select id=\"" + selSingle + "\" parameterType=\"String\" resultType=\"object\">\n" +
				"${value}\n" +
				"</select>\n\n" +
				"<select id=\"" + selHashMap + "\" parameterType=\"String\" resultType=\"hashmap\">\n" +
				"${value}\n" +
				"</select>\n\n";				
				
		for(Table tab : sh.tables)
		{
			code += tab.generateInsertCode();
			//code += tab.generateSelectCode();
		}
		
		code += "</mapper>";
		return code;	
	}
	
	
	private void initSchema(Schema sh)
	{
		sh.createTables();
		sh.primaryPopulateTables();
		sh.populateForeignKeys();
		sh.postProcessPopulation();
	}
	
	
	public static SqlSession tempSessionFactory()
	{
		return sqlMapper.openSession();
	}
	
	public static SqlSession sessionFactory()
	{		
		return trgMapper.openSession();
	}	
	
	public Schema getSchema()
	{
		return schema;
	}


	public void setSchema(Schema schema)
	{
		this.schema = schema;
	}

}





/**
 * TODO :
 * 
 * +odczyt plików guava
 * - tworzenie "obiektów", własna klasa : wartość, nazwa, popularność/całkowita suma(statyczna, w mapie po nazwie)
 * - metody dekodujące string -> "obiekt"
 * - połączenie do bazy mybatisem i tworzenie nowego pliku bazy
 * - tworzenie tabel
 *  
 *  
 *  Struktura : 
 *  - źródła wczytują dane
 *  --	interfejs źródła : 
 *  	  String[] get(int number) : zwraca określoną ilość "wygenerowanych" (odpowiednio odczytanych/zdublowanych wierszy
 *  	  String get() : zwraca pojedyńcze dane
 *  
 *  - generator
 *  --  interfejs :
 *  	  konstruktor (źródła List)
 *  
 *  
 *  
 *  
 *  opis działania : źródła dostarczają tablic string. W ramach tabeli istnieją kolumny, którymi są te źródła. Tabela składa się z kolumn, lecz
 *  	niektóre kolumny są puste - takie jak klucze obce czy kolumny zależne. Etap pośredni to wypełnione tabele z możliwymi kolumnami pustymi
 *  Integrator : moduł spajający tabele
 *  
 *  
 *  przypadek generowania osób - rodzin. Warunki do spełnienia : osoby mogą tworzyć rodziny. Rodzina to 2 (czasem 1) osoby o takim samym nazwisku jako rodzice, 
 *  następnie możliwe dzieci które są młodsze od rodziców o 18 lat (definiowane jako parametr, kolejnymi osobami są dziadkowie od strony obojga starsi o co najmniej 18 lat 
 *  (zakres do definiowania). potrzebny jest generator wierszy uwzględniający logikę biznesową. Generator pobiera dane ze źródła
 *    Generator jest specyficzny dla danej dziedziny, jako parametry przyjmuje niezbędne źródła (np źródła imion, nazwisk, miast i ulic)
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 *  
 * 
 */
